﻿using System;
using System.Collections.Generic;
using ChainAnalises.Classes.AuxiliaryClasses.DataManipulators.SpaceRebuilders;
using ChainAnalises.Classes.IntervalAnalysis;
using ChainAnalises.Classes.IntervalAnalysis.Characteristics;
using ChainAnalises.Classes.PhantomChains;
using ChainAnalises.Classes.Root.SimpleTypes;
using ChainAnalises.Classes.Statistics.MarkovChain.Generators;
using PhantomChainsAnalyser.View;

namespace PhantomChainsAnalyser.Model
{
    public class Controller
    {
        private DataContainer Data = null;
        private ResultContainer Result = null;

        public Controller(DataContainer data, ResultContainer Answer)
        {
            if ((data == null) || (data.table == null) || (data.DRQuery == null))
            {
                throw new Exception("Нет данных для обработки");
            }
            Data = data;
            lock (Answer)
            {
                if ((Answer == null) || (Answer.AverageGeometricalInterval == null) || (Answer.Entropy == null) || (Answer.Regularity == null))
                {
                    throw new Exception("Некуда положить результаты");
                }
                Result = Answer;
            }
        }

        public void Calculate()
        {
            Drawer drawer = new Drawer();
            drawer.Clear(Data.Control1);
            drawer.Clear(Data.Control2);
            drawer.Clear(Data.Control3);
            Chain InputChain = GetInputChain();
            if (InputChain.Alpahbet.power > 4)
            {
                lock (Result)
                {
                    Result.InvalidChain = true;
                    Result.Finished = true;
                }
                return;
            }
            NullRebuilder<BaseChain, Chain> BaseRebuilder = new NullRebuilder<BaseChain, Chain>();
            NullRebuilder<Chain, BaseChain> Rebuilder = new NullRebuilder<Chain, BaseChain>();

            BaseChain AminoChain = Coder.Encode(BaseRebuilder.Rebuild(InputChain));
            Chain PhantomChain = Rebuilder.Rebuild(Coder.Decode(AminoChain));

            PhantomChainGenerator<Chain, Chain> Generator = new PhantomChainGenerator<Chain, Chain>(PhantomChain, new SimpleGenerator());
            List<BaseChain> ResultChains = Generator.Generate((uint)Data.count);

            for (int j = 0; j < ResultChains.Count; j++)
            {
                lock (Result)
                {
                    Result.GeneratedChains.Add(Rebuilder.Rebuild(ResultChains[j]));
                    Result.Entropy.AddValue(Result.GeneratedChains[j].GetCharacteristic(LinkUp.Both, CharacteristicsFactory.H));
                    Result.AverageGeometricalInterval.AddValue(Result.GeneratedChains[j].GetCharacteristic(LinkUp.Both, CharacteristicsFactory.deltaG));
                    Result.Regularity.AddValue(Result.GeneratedChains[j].GetCharacteristic(LinkUp.Both, CharacteristicsFactory.r));
                }
            }
            double Regularity = InputChain.GetCharacteristic(LinkUp.Both, CharacteristicsFactory.r);
            double AverageGeometricalInterval = InputChain.GetCharacteristic(LinkUp.Both, CharacteristicsFactory.deltaG);
            double Entropy = InputChain.GetCharacteristic(LinkUp.Both, CharacteristicsFactory.H);
            lock (Result)
            {
                Result.InputChainRegularity = Regularity;
                Result.InputChainEntropy = Entropy;
                Result.InputChainAverageGeometricalInterval = AverageGeometricalInterval;
                Result.InputChain = InputChain;
                Result.AminoChain = AminoChain;
                Result.PhantomChain = PhantomChain;
                Result.Finished = true;
            }
            lock(Result)
            {
                drawer.DrawGraph(Data.Control2, Result.Entropy, 0,Result.InputChainEntropy);
                drawer.DrawGraph(Data.Control1, Result.Regularity, 1, Result.InputChainRegularity);
                drawer.DrawGraph(Data.Control3, Result.AverageGeometricalInterval, 2, Result.InputChainAverageGeometricalInterval);
            }
        }

        private Chain GetInputChain()
        {
            int ChainLength = Convert.ToInt32(Data.table.Rows[Data.number].Cells[1].Value);
            string chain = Data.table.Rows[Data.number].Cells[2].Value.ToString();
            Chain TempInputChain = new Chain(ChainLength);
            int RealChainLength = 0;
            for (int i = 0; i < ChainLength; i++)
            {
                if ((chain[i] != '\n') && (chain[i] != ' ') && (chain[i] != '\r'))
                {
                    TempInputChain[RealChainLength] = new ValueChar(chain[i]);
                }
                else
                {
                    RealChainLength--;
                }
                RealChainLength++;
            }
            Chain InputChain = new Chain(RealChainLength);
            for (int k = 0; k < RealChainLength; k++)
            {
                InputChain[k] = TempInputChain[k];
            }
            return InputChain;
        }
    }
}
